package com.mayn.util;

import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.HttpURLConnection;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.Proxy;
import java.net.URL;
import java.net.URLConnection;
import java.net.UnknownHostException;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Map.Entry;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.zip.GZIPInputStream;

import javax.servlet.http.HttpServletRequest;

import org.apache.http.HttpEntity;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.mime.MultipartEntityBuilder;
import org.apache.http.entity.mime.content.FileBody;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.protocol.BasicHttpContext;
import org.apache.http.util.EntityUtils;
import org.openqa.selenium.Cookie;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;

import net.dongliu.requests.Requests;

/**
 * HTTP POST和GET处理工具类
 * 
 * @author dadao
 * @date 2016-05-05 14:00
 */
public class HttpUtil {

	static String proxyHost = "127.0.0.1";
	static String proxyPort = "8888";
	static boolean isProxy = Boolean.valueOf(PropertiesUtil.getConfig("isProxy")) ? Boolean.valueOf(PropertiesUtil.getConfig("isProxy")) : false;
	
	private static final Logger LOG = LoggerFactory.getLogger(HttpUtil.class);

	public static String sendGet(String url) {
		return sendGet(url, null, null);
	}

	public static String sendGet(String url, HashMap<String, String> params) {
		return sendGet(url, params, null);
	}

	public static String sendGet(String url, HashMap<String, String> params, HashMap<String, String> headers) {
		return sendGetWithRequests(url, params, headers);
	}

	public static String sendGetWithRequests(String url, HashMap<String, String> params, HashMap<String, String> headers) {
		String resp = "";
		if ((headers != null && !headers.isEmpty()) && (params != null && !params.isEmpty())) {
			resp = Requests.get(url).headers(headers).params(params).send().readToText();
		}
		if ((headers != null && !headers.isEmpty())) {
			resp = Requests.get(url).headers(headers).send().readToText();
		}
		if ((params != null && !params.isEmpty())) {
			resp = Requests.get(url).params(params).send().readToText();
		}
		//System.out.println("----------response:" + resp);
		return resp;
	}
	
	/**
	 * 向指定URL发送GET方法的请求
	 * 
	 * @param url
	 * @param params
	 * @param header
	 * @return
	 */
	public static String sendGetWithURLConnection(String url, LinkedHashMap<String, String> params, HashMap<String, String> headers) {
		return sendGetWithURLConnection(url,params,headers,"UTF-8",false);
	}
	
	public static String sendGetWithURLConnection(String url, LinkedHashMap<String, String> params, HashMap<String, String> headers,String charsetStr) {
		return sendGetWithURLConnection(url,params,headers,charsetStr,false);
	}
	
	public static String sendGetWithURLConnection(String url, LinkedHashMap<String, String> params, HashMap<String, String> headers,String charsetStr,Boolean isRedirect) {
		String result= "";
		try{
			result = getSendGetWithURLConnectionResult(url,params,headers,charsetStr,isRedirect).get("result").toString();
		}catch(Exception e1){
			LOG.error("第一次采集失败,重试1次");
			try{
				result = getSendGetWithURLConnectionResult(url,params,headers,charsetStr,isRedirect).get("result").toString();
			}catch(Exception e2){
				LOG.error("第一次采集失败,重试2次");
				try{
					result = getSendGetWithURLConnectionResult(url,params,headers,charsetStr,isRedirect).get("result").toString();
				}catch(Exception e3){
					
				}
			}
			
		}
		return result;
	}
	
	public static HashMap<String, Object> getSendGetWithURLConnectionResult(String url, LinkedHashMap<String, String> params, HashMap<String, String> headers) {
		return getSendGetWithURLConnectionResult(url, params, headers,"UTF-8",false);
	}

	/**
	 * @param url
	 * @param params
	 * @param headers
	 * @param charsetStr 编码
	 * @param isRedirect 是否支持重定向
	 * @return
	 */
	public static HashMap<String, Object> getSendGetWithURLConnectionResult(String url, LinkedHashMap<String, String> params, HashMap<String, String> headers,String charsetStr,Boolean isRedirect) {
		HashMap<String, Object> object = new HashMap<String, Object>();
		// 代理
		Proxy proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress(proxyHost, Integer.parseInt(proxyPort)));
		String result = "";
		BufferedReader in = null;
		try {
			String urlNameString = url;
			/** 组装参数 **/
			String param = parseParams(params);
			if(param!=null && !param.equals("")){
				urlNameString = url + "?" + param;
			}
			URL realUrl = new URL(urlNameString);
			// https忽略证书
			if ("https".equalsIgnoreCase(realUrl.getProtocol())) {
				SslUtils.ignoreSsl();
			}
			/** 打开和URL之间的连接 **/
			URLConnection conn = null;
			if (isProxy) {
				conn = realUrl.openConnection(proxy);
			} else {
				conn = realUrl.openConnection();
			}
			/** 设置header **/
			if (headers != null && !headers.isEmpty()) {
				for (Entry<String, String> e : headers.entrySet()) {
					conn.setRequestProperty(e.getKey(), e.getValue());
				}
			} else {
				/** 设置通用的请求属性 **/
				conn.setRequestProperty("accept", "*/*");
				conn.setRequestProperty("connection", "Keep-Alive");
				conn.setRequestProperty("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");
			}
			/** 建立实际的连接 **/
			conn.connect();
			String encoding = conn.getContentEncoding();
			if (encoding != null && encoding.contains("gzip")) {// 首先判断服务器返回的数据是否支持gzip压缩，
				InputStream is = new BufferedInputStream(conn.getInputStream());
				is = new GZIPInputStream(is); // 如果支持则应该使用GZIPInputStream解压，否则会出现乱码无效数据
				in = new BufferedReader(new InputStreamReader(is, charsetStr));
				String line;
				while ((line = in.readLine()) != null) {
					result += line;
				}
			} else {
				/** 定义 BufferedReader输入流来读取URL的响应 **/
				in = new BufferedReader(new InputStreamReader(conn.getInputStream(), charsetStr));
				String line;
				while ((line = in.readLine()) != null) {
					result += line;
				}
			}
			Map<String, List<String>> responseHeaders = conn.getHeaderFields();
			//是否支持301重定向
			if(isRedirect){
				String newUrl = null;
				if(((HttpURLConnection)conn).getResponseCode() ==301){
					if(responseHeaders.containsKey("Location")){
						newUrl = responseHeaders.get("Location").toString();
						if(newUrl.contains("[")){
							newUrl = newUrl.replace("[", "");
						}
						if(newUrl.contains("]")){
							newUrl = newUrl.replace("]", "");
						}
					}
					if(newUrl!=null && !HttpUtil.getCleanUrl(newUrl).equals(HttpUtil.getCleanUrl(url))){
						result = HttpUtil.sendGetWithURLConnection(newUrl, params, headers, charsetStr,false);
					}
				}
			}
			object.put("result", result);
			object.put("responseHeaders", responseHeaders);
			String cookie = "";
			if(responseHeaders.containsKey("Set-Cookie")){
				cookie = responseHeaders.get("Set-Cookie").toString();
			}
			object.put("cookie", cookie);
		} catch (Exception e) {
			System.out.println("发送GET请求出现异常！" + e);
			e.printStackTrace();
		} finally {/** 使用finally块来关闭输入流 **/
			try {
				if (in != null) {
					in.close();
				}
			} catch (Exception e2) {
				e2.printStackTrace();
			}
		}
		return object;
	}

	public static String sendPost(String url, LinkedHashMap<String, String> params) {
		return sendPostWithURLConnection(url, params, null);
	}

	public static String sendPost(String url, String userAgent, HashMap<String, String> params) {
		String resp = "";
		if ((params != null && !params.isEmpty()) && (userAgent != null && !userAgent.isEmpty())) {
			resp = Requests.post(url).userAgent(userAgent).params(params).send().readToText();
		}
		if ((params != null && !params.isEmpty())) {
			resp = Requests.post(url).params(params).send().readToText();
		}
		return resp;
	}

	public static String sendPost(String url, HashMap<String, String> params, HashMap<String, String> headers) {
		String resp = "";
		if ((params != null && !params.isEmpty()) && (headers != null && !headers.isEmpty())) {
			resp = Requests.post(url).params(params).headers(headers).send().readToText();
		}
		if ((params != null && !params.isEmpty())) {
			resp = Requests.post(url).params(params).send().readToText();
		}
		return resp;
	}

	public static String sendPost(String url, String userAgent, LinkedHashMap<String, String> params, HashMap<String, String> headers) {
		String resp = "";
		if ((userAgent != null && !userAgent.isEmpty()) && (params != null && !params.isEmpty()) && (headers != null && !headers.isEmpty())) {
			resp = Requests.post(url).userAgent(userAgent).params(params).headers(headers).send().readToText();
		}
		if ((params != null && !params.isEmpty())) {
			resp = Requests.post(url).params(params).send().readToText();
		}
		return resp;
	}
	
	public static String sendPostWithURLConnection(String url, LinkedHashMap<String, String> params, HashMap<String, String> headers) {
		return sendPostWithURLConnection(url, params,headers,"UTF-8");
	}

	/***
	 * 向指定URL发送POST方法的请求
	 * 
	 * @param url
	 * @param params
	 * @param header
	 * @return
	 */
	public static String sendPostWithURLConnection(String url, LinkedHashMap<String, String> params, HashMap<String, String> headers,String charsetStr) {
		// 代理
		Proxy proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress(proxyHost, Integer.parseInt(proxyPort)));
		PrintWriter out = null;
		BufferedReader in = null;
		String result = "";
		try {
			URL realUrl = new URL(url);
			// https忽略证书
			if ("https".equalsIgnoreCase(realUrl.getProtocol())) {
				SslUtils.ignoreSsl();
			}
			/** 打开和URL之间的连接 **/
			URLConnection conn = null;
			if (isProxy) {
				conn = realUrl.openConnection(proxy);
			} else {
				conn = realUrl.openConnection();
			}
			/** 设置header **/
			if (headers != null && !headers.isEmpty()) {
				for (Entry<String, String> e : headers.entrySet()) {
					conn.setRequestProperty(e.getKey(), e.getValue());
				}
			} else {
				/** 设置通用的请求属性 **/
				conn.setRequestProperty("accept", "*/*");
				conn.setRequestProperty("connection", "Keep-Alive");
				conn.setRequestProperty("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");
			}

			/** 发送POST请求必须设置如下两行 **/
			conn.setDoOutput(true);
			conn.setDoInput(true);
			/** 获取URLConnection对象对应的输出流 **/
			out = new PrintWriter(conn.getOutputStream());
			/** 发送请求参数 **/
			String param = parseParams(params);
			out.print(param);
			/** flush输出流的缓冲 **/
			out.flush();
			/** 定义BufferedReader输入流来读取URL的响应 **/
			
			String encoding = conn.getContentEncoding();			
			if (encoding != null && encoding.contains("gzip")) {// 首先判断服务器返回的数据是否支持gzip压缩，
				InputStream is = new BufferedInputStream(conn.getInputStream());
				is = new GZIPInputStream(is); // 如果支持则应该使用GZIPInputStream解压，否则会出现乱码无效数据
				in = new BufferedReader(new InputStreamReader(is,charsetStr));
				String line;
				while ((line = in.readLine()) != null) {
					result += line;
				}
				
			} else {
				/** 定义 BufferedReader输入流来读取URL的响应 **/
				in = new BufferedReader(new InputStreamReader(conn.getInputStream(), charsetStr));
				String line;
				while ((line = in.readLine()) != null) {
					result += line;
				}
			}
		} catch (Exception e) {
			System.out.println("发送 POST 请求出现异常！" + e);
			e.printStackTrace();
		} finally { /** 使用finally块来关闭输出流、输入流 **/
			try {
				if (out != null) {
					out.close();
				}
				if (in != null) {
					in.close();
				}
			} catch (IOException ex) {
				ex.printStackTrace();
			}
		}
		return result;
	}
	
	/**
	 * PlayLoad POST请求
	 * @param url
	 * @param payload
	 * @param headers
	 * @return
	 */
	public static String sendPostWithURLConnection(String url, String payload, HashMap<String, String> headers) {
        PrintWriter out = null;
        BufferedReader in = null;
        String result = "";
        try {
            URL realUrl = new URL(url);
            /** 打开和URL之间的连接 **/
            HttpURLConnection conn =  (HttpURLConnection) realUrl.openConnection();
            /** 设置通用的请求属性 **/
            conn.setRequestProperty("accept", "*/*");
            conn.setRequestProperty("connection", "Keep-Alive");
            conn.setRequestProperty("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");
           	conn.setRequestMethod("POST");
           	conn.setRequestProperty("Accept", "application/json");
           	conn.setRequestProperty("Content-Type", "application/json; charset=UTF-8");
            /** 设置header **/
            if (headers != null && !headers.isEmpty()) {
                for (Map.Entry<String, String> e : headers.entrySet()) {
                    conn.setRequestProperty(e.getKey(), e.getValue());
                }
            }
            /** 发送POST请求必须设置如下两行 **/
            conn.setDoOutput(true);
            conn.setDoInput(true);
            /** 获取URLConnection对象对应的输出流 **/
            OutputStreamWriter writer = new OutputStreamWriter(conn.getOutputStream(), "UTF-8");
            /** 发送请求参数 payload**/
            writer.write(payload);
            writer.close();
            /** 定义BufferedReader输入流来读取URL的响应 **/
            BufferedReader br = new BufferedReader(new InputStreamReader(conn.getInputStream()));
            StringBuffer jsonString = new StringBuffer();
            String line;
            while ((line = br.readLine()) != null) {
                 jsonString.append(line);
            }
            result = jsonString.toString();
            br.close();
            conn.disconnect();
        } catch (Exception e) {
            System.out.println("发送 POST 请求出现异常！" + e);
            e.printStackTrace();
        } finally { /** 使用finally块来关闭输出流、输入流 **/
            try {
                if (out != null) {
                    out.close();
                }
                if (in != null) {
                    in.close();
                }
            } catch (IOException ex) {
                ex.printStackTrace();
            }
        }
        return result;
    }

	/**
	 * 将HashMap参数组装成字符串
	 * 
	 * @param map
	 * @return
	 */
	public static String parseParams(LinkedHashMap<String, String> map) {
		StringBuffer sb = new StringBuffer();
		String ret ="";
		if (map != null) {
			for (Entry<String, String> e : map.entrySet()) {
				sb.append(e.getKey());
				sb.append("=");
				sb.append(e.getValue());
				sb.append("&");
			}
			ret = sb.substring(0, sb.length() - 1);
		}
		return ret;
	}

	/**
	 * 获取客户端Ip
	 *
	 * @param request
	 * @return
	 */
	public static String getClientIp(HttpServletRequest request) {
		String ip = request.getHeader("x-forwarded-for");
		if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
			ip = request.getHeader("Proxy-Client-IP");
		}
		if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
			ip = request.getHeader("WL-Proxy-Client-IP");
		}
		if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
			ip = request.getRemoteAddr();
		}
		return ip.equals("0:0:0:0:0:0:0:1") ? "127.0.0.1" : ip;
	}

	/**
	 * 获取服务器IP
	 *
	 * @return
	 */
	public static String getLocalIP() {
		InetAddress addr;
		String ipAddrStr = "";
		try {
			addr = InetAddress.getLocalHost();
			byte[] ipAddr = addr.getAddress();
			for (int i = 0; i < ipAddr.length; i++) {
				if (i > 0) {
					ipAddrStr += ".";
				}
				ipAddrStr += ipAddr[i] & 0xFF;
			}
		} catch (UnknownHostException e) {
			return null;
			// e.printStackTrace();
		}
		return ipAddrStr;
	}

	/**
	 * URL中host部分截取
	 * 
	 * @param url
	 * @return
	 */
	public static String getHost(String url) {
		if (url == null || url.trim().equals("")) {
			return "";
		}
		String host = "";
		Pattern p = Pattern.compile("(?<=//|)((\\w)+\\.)+\\w+");
		Matcher matcher = p.matcher(url);
		if (matcher.find()) {
			host = matcher.group();
		}
		return host;
	}

	/**
	 * Set<Cookie> 转换为 字符串
	 * 
	 * @param cookieSet
	 * @return
	 */
	public static String getCookieStr(Set<Cookie> cookieSet) {
		String cookieStr = "";
		if (cookieSet == null) {
			return cookieStr;
		} else {
			for (Cookie ck : cookieSet) {
				cookieStr = cookieStr + ";" + ck.getName() + "=" + ck.getValue();
			}
			if (cookieStr.startsWith(";")) {
				cookieStr = cookieStr.substring(1, cookieStr.length());
			}
		}
		return cookieStr;
	}
	
	/** 
     *正则匹配 
     *  
     * @param s 
     * @param pattern 
     * @return 
     */  
    public static boolean matcher(String s, String pattern) {  
        Pattern p = Pattern.compile(pattern, Pattern.CASE_INSENSITIVE + Pattern.UNICODE_CASE);  
        Matcher matcher = p.matcher(s);  
        if (matcher.find()) {  
            return true;  
        } else {  
            return false;  
        }  
    }  
	
	/** 
     *获取Response内容字符集 
     *  
     * @param response 
     * @return 
     */  
    public static String getContentCharset(String headerHtml) {  
        String charset = "ISO_8859-1";  
        if (headerHtml != null) {  
            if (matcher(headerHtml, "(charset)\\s?=\\s?(utf-?8)")) {  
                charset = "utf-8";  
            } else if (matcher(headerHtml, "(charset)\\s?=\\s?(gbk)")) {  
                charset = "gbk";  
            } else if (matcher(headerHtml, "(charset)\\s?=\\s?(gb2312)")) {  
                charset = "gb2312";// http://ks.examda.com  
            }  
        }  
        return charset;  
    }  
    
    
    /**
     * 上传文件
     * @param url
     * @param file
     * @return
     */
	public static JSONObject uploadMedia(String url, File file) {
		
		HttpPost httpPost = new HttpPost(url);
        CloseableHttpResponse response = null;
        CloseableHttpClient httpClient = HttpClients.createDefault();
        RequestConfig requestConfig = RequestConfig.custom().setSocketTimeout(2000).setConnectTimeout(2000).build();
        httpPost.setConfig(requestConfig);

        HttpEntity requestEntity = MultipartEntityBuilder.create().addPart("media",
        		new FileBody(file, ContentType.APPLICATION_OCTET_STREAM, file.getName())).build();
        httpPost.setEntity(requestEntity);

        try {
            response = httpClient.execute(httpPost, new BasicHttpContext());

            if (response.getStatusLine().getStatusCode() != 200) {

                System.out.println("request url failed, http code=" + response.getStatusLine().getStatusCode()
                                   + ", url=" + url);
                return null;
            }
            HttpEntity entity = response.getEntity();
            if (entity != null) {
                String resultStr = EntityUtils.toString(entity, "utf-8");
                JSONObject result = JSON.parseObject(resultStr);
                if (result.getInteger("errcode") == 0) {
                    // 成功
                	result.remove("errcode");
                	result.remove("errmsg");
                    return result;
                } else {
                    System.out.println("request url=" + url + ",return value=");
                    System.out.println(resultStr);
                    @SuppressWarnings("unused")
					int errCode = result.getInteger("errcode");
                    String errMsg = result.getString("errmsg");
                    LOG.error(errMsg);
                }
            }
        } catch (IOException e) {
            System.out.println("request url=" + url + ", exception, msg=" + e.getMessage());
            e.printStackTrace();
        } finally {
            if (response != null) try {
                response.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        return null;
	}
	

	/**
	 * http文件下载
	 * 
	 * @param urlPath
	 * @return
	 */

	public static byte[] downloadFile(String urlPath) {
		try {
			URL url = new URL(urlPath);
			HttpURLConnection conn = (HttpURLConnection) url.openConnection();
			conn.setRequestMethod("GET");
			conn.setConnectTimeout(5 * 1000);
			InputStream inStream = conn.getInputStream();// 通过输入流获取文件数据
			byte[] byteData = readInputStream(inStream);// 得到文件的二进制数据
			return byteData;
		} catch (Exception e) {
			e.printStackTrace();
		}
		return null;
	}
	

	private static byte[] readInputStream(InputStream inStream) throws IOException {
		ByteArrayOutputStream outStream = new ByteArrayOutputStream();
		byte[] buffer = new byte[10240];
		int len = 0;
		while ((len = inStream.read(buffer)) != -1) {
			outStream.write(buffer, 0, len);
		}
		inStream.close();
		return outStream.toByteArray();
	}
	
	public static String getCleanUrl(String url){
		if(url.contains("https://")){
			url = url.replace("https://", "");
		}
		if(url.contains("http://")){
			url = url.replace("http://", "");
		}
		return url;
	}
}
